<?php

namespace Service\Http;

use Exception;
use JsonException;
use ReflectionClass;
use ReflectionException;
use Service\App;
use Service\Http\Exception\RestException;

class Kernel
{

    public function capture()
    {
        try {
            $request = $this->createRequestContext();
            $response_payload = $this->handleRequest($request);
        } catch (Exception $e) {
            $response_payload = $this->exceptionResponse($e);
        }
        echo $response_payload;
    }

    /**
     * @throws RestException
     */
    private function createRequestContext(): Request
    {
        if (isset($_SERVER['HTTP_ROUTE_PATH'])) {
            $method = $_SERVER['REQUEST_METHOD'];
            $route = $_SERVER['HTTP_ROUTE_PATH'];
        } else {
            throw new RestException("http header loss `route-path` img", 400);
        }
        if ($method === 'POST') {
            $payload = json_decode(file_get_contents('php://input'), true);
            return new Request($method, $route, $_GET, $payload);
        } else {
            return new Request($method, $route, $_GET);
        }
    }

    /**
     * @throws ReflectionException
     */
    private function middleware(Request $request)
    {
        foreach (App::$middleware as $middleware_name) {
            $class = new ReflectionClass($middleware_name);
            $instance = $class->newInstance();
            $instance->handle($request);
        }
    }

    /**
     * @throws RestException
     */
    private
    function handleRequest(Request $request): string
    {
        try {
            self::middleware($request);
        } catch (ReflectionException $e) {
            throw new RestException('服务器中间件加载异常');
        } catch (Exception $e) {
            throw new RestException('服务器中间件处理异常');
        }
        $ajaxResponse = Route::handle($request);
        try {
            return json_encode($ajaxResponse, JSON_THROW_ON_ERROR);
        } catch (JsonException $e) {
            throw new RestException('服务器JSON序列化错误');
        }
    }

    private
    function exceptionResponse(Exception $e): string
    {
        http_response_code($e->getCode());
        return '{"message": "' . $e->getMessage() . '"}';
    }
}
